package com.demo.netty.service;

import com.demo.netty.entity.MessageEntity;
import com.demo.netty.model.ChatMessage;
import com.demo.netty.repository.MessageRepository;
import com.demo.netty.session.SessionManager;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class ChatService {
    private static final Logger logger = LoggerFactory.getLogger(ChatService.class);

    @Autowired
    private SessionManager sessionManager;

    @Autowired
    private MessageRepository messageRepository;

    @Autowired
    private ReconnectService reconnectService;

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 处理消息
     */
    public void handleMessage(Channel channel, ChatMessage message) {
        try {
            // 添加空值检查
            if (channel == null) {
                logger.error("Channel is null, cannot handle message");
                return;
            }
            
            if (message == null) {
                logger.error("Message is null, cannot handle message");
                return;
            }
            
            switch (message.getType()) {
                case JOIN:
                    handleUserJoin(channel, message);
                    break;
                case CHAT:
                    handleChatMessage(channel, message);
                    break;
                case LEAVE:
                    handleUserLeave(channel, message);
                    break;
                default:
                    logger.warn("未知的消息类型: {}", message.getType());
            }
        } catch (Exception e) {
            logger.error("处理消息失败", e);
        }
    }

    /**
     * 处理用户加入
     */
    private void handleUserJoin(Channel channel, ChatMessage message) {
        // 添加空值检查
        if (message.getSender() == null || message.getSender().isEmpty()) {
            logger.error("用户加入消息发送者为空");
            return;
        }

        sessionManager.userOnline(message.getSender(), channel);

        // 发送离线消息
        sendOfflineMessages(message.getSender(), channel);

        // 广播用户加入消息
        ChatMessage joinMessage = new ChatMessage(message.getSender() + " 加入了聊天", "系统", null, ChatMessage.MessageType.SYSTEM);

        try {
            sessionManager.broadcast(new TextWebSocketFrame(objectMapper.writeValueAsString(joinMessage)));
        } catch (Exception e) {
            logger.error("广播用户加入消息失败", e);
        }
    }

    /**
     * 发送离线消息给用户
     */
    private void sendOfflineMessages(String userId, Channel channel) {
        // 先发送内存中的离线消息
        ChatMessage offlineMessage = sessionManager.getOfflineMessage(userId);
        if (offlineMessage != null) {
            try {
                // 发送离线消息给用户
                channel.writeAndFlush(new TextWebSocketFrame(objectMapper.writeValueAsString(offlineMessage)));
                logger.info("发送内存中的离线消息给用户 {}", userId);
            } catch (Exception e) {
                logger.error("发送离线消息失败", e);
            }
        }

        // 再从数据库获取离线消息并发送
        List<ChatMessage> dbOfflineMessages = getOfflineMessages(userId);
        for (ChatMessage message : dbOfflineMessages) {
            try {
                channel.writeAndFlush(new TextWebSocketFrame(objectMapper.writeValueAsString(message)));
                // 标记消息为已读
                markMessageAsRead(message);
            } catch (Exception e) {
                logger.error("发送数据库离线消息失败", e);
            }
        }
        logger.info("发送数据库中的 {} 条离线消息给用户 {}", dbOfflineMessages.size(), userId);
    }

    /**
     * 处理聊天消息
     */
    private void handleChatMessage(Channel channel, ChatMessage message) {
        logger.info("处理聊天消息: {}", message);

        try {
            // 如果是私聊消息
            if (message.getReceiver() != null && !message.getReceiver().isEmpty()) {
                sendPrivateMessage(message);
            } else {
                // 广播消息
                sessionManager.broadcast(new TextWebSocketFrame(objectMapper.writeValueAsString(message)));
            }
        } catch (Exception e) {
            logger.error("处理聊天消息失败", e);
        }
    }

    /**
     * 发送私聊消息
     */
    private void sendPrivateMessage(ChatMessage message) {
        // 添加空值检查
        if (message.getReceiver() == null || message.getReceiver().isEmpty()) {
            logger.error("私聊消息接收者为空");
            return;
        }
        
        Channel receiverChannel = sessionManager.getUserChannel(message.getReceiver());

        try {
            if (receiverChannel != null && receiverChannel.isActive()) {
                // 接收者在线，直接发送
                receiverChannel.writeAndFlush(new TextWebSocketFrame(objectMapper.writeValueAsString(message)));
            } else {
                // 接收者不在线，保存为离线消息
                sessionManager.saveOfflineMessage(message.getReceiver(), message);
                logger.info("用户 {} 不在线，消息已保存为离线消息", message.getReceiver());
            }
        } catch (Exception e) {
            logger.error("发送私聊消息失败", e);
        }
    }

    /**
     * 处理用户离开
     */
    private void handleUserLeave(Channel channel, ChatMessage message) {
        // 添加空值检查
        if (message.getSender() == null || message.getSender().isEmpty()) {
            logger.error("用户离开消息发送者为空");
            return;
        }
        
        sessionManager.userOffline(message.getSender());

        // 广播用户离开消息
        ChatMessage leaveMessage = new ChatMessage(message.getSender() + " 离开了聊天", "系统", null, ChatMessage.MessageType.SYSTEM);

        try {
            sessionManager.broadcast(new TextWebSocketFrame(objectMapper.writeValueAsString(leaveMessage)));
        } catch (Exception e) {
            logger.error("广播用户离开消息失败", e);
        }
    }

    /**
     * 处理用户断开连接
     */
    public void handleUserDisconnect(Channel channel) {
        // 这里可以实现更复杂的逻辑来处理用户断线
        // 比如标记用户为离线状态，而不是直接移除
        logger.info("用户连接断开");
    }

    /**
     * 保存消息到数据库
     */
    public void saveMessage(ChatMessage message) {
        try {
            MessageEntity messageEntity = convertToEntity(message);
            messageRepository.save(messageEntity);
            logger.info("消息已保存到数据库");
        } catch (Exception e) {
            logger.error("保存消息到数据库失败", e);
        }
    }

    /**
     * 获取用户的离线消息
     */
    public List<ChatMessage> getOfflineMessages(String userId) {
        try {
            List<MessageEntity> entities = messageRepository.findByReceiverAndIsOfflineMessageTrue(userId);
            List<ChatMessage> messages = new ArrayList<>();
            for (MessageEntity entity : entities) {
                messages.add(convertToMessage(entity));
            }
            return messages;
        } catch (Exception e) {
            logger.error("获取离线消息失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 标记消息为已读
     */
    public void markMessageAsRead(ChatMessage message) {
        try {
            // 这里需要根据实际情况实现标记消息为已读的逻辑
            logger.info("消息已标记为已读");
        } catch (Exception e) {
            logger.error("标记消息为已读失败", e);
        }
    }
    
    /**
     * 将 ChatMessage 转换为 MessageEntity
     */
    private MessageEntity convertToEntity(ChatMessage message) {
        MessageEntity entity = new MessageEntity();
        entity.setContent(message.getContent());
        entity.setSender(message.getSender());
        entity.setReceiver(message.getReceiver());
        entity.setType(message.getType().name());
        entity.setTimestamp(message.getTimestamp());
        entity.setOfflineMessage(message.isOfflineMessage());
        return entity;
    }
    
    /**
     * 将 MessageEntity 转换为 ChatMessage
     */
    private ChatMessage convertToMessage(MessageEntity entity) {
        ChatMessage message = new ChatMessage();
        message.setContent(entity.getContent());
        message.setSender(entity.getSender());
        message.setReceiver(entity.getReceiver());
        message.setType(ChatMessage.MessageType.valueOf(entity.getType()));
        message.setTimestamp(entity.getTimestamp());
        message.setOfflineMessage(entity.isOfflineMessage());
        return message;
    }
}